package com.dfqy.front;

import com.dfqy.pojo.User;
import com.dfqy.service.UserService;
import com.dfqy.util.*;
import com.dfqy.vo.Result;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.*;
import javax.validation.constraints.NotBlank;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Author : atyushu
 * Package : com.dfqy.front
 * ClassName : UserFrontController
 * Create : 2023/7/31 - 13:53
 * Version : v1.0
 * Description : The class of controller for user.
 */
@Validated
@RestController
@Api(tags = "UserFrontController", description = "用户")
@RequestMapping("front/user")
public class UserFrontController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${upload-path}")
    private String imagePath;

    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        simpleDateFormat.setLenient(false);
        webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(simpleDateFormat, true));
    }

    @ApiOperation("用户登录, (着重注意: 用户成功登录后, 后端会返回一个key, 前端务必将此key存入session中, 例如: window.sessionStorage.setItem('token', result.data); )")
    @PostMapping("signIn")
    public Result signIn(@RequestParam("uname") @ApiParam(name = "uname", value = "用户名", required = true) @NotBlank(message = "用户名不能为空") String uname,
                         @RequestParam("pass") @ApiParam(name = "pass", value = "密码", required = true) @NotBlank(message = "密码不能为空") String pass,
                         @RequestParam("vcode") @ApiParam(name = "vcode", value = "验证码", required = true) @NotBlank(message = "验证码不能为空") String vcode,
                         @RequestParam("uid") @ApiParam(name = "uid", value = "验证码uid", required = true) @NotBlank(message = "验证码uid不能为空") String uid
    ) {
        if (redisTemplate.opsForValue().get("vcode::" + uid) == null) {
            return Result.error("验证码已超时");
        }
        if (!redisTemplate.opsForValue().get("vcode::" + uid).equals(vcode)) {
            return Result.error("验证码错误");
        }
        User user = userService.signIn(uname, Md5Utils.hash(pass));
        if (user != null) {
            if (user.getIsvalid() == 0) {
                return Result.error("账号已被封禁");
            }
            user.setScore(user.getScore() + 10);
            userService.update(user);
            String key = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
            return Result.success(key, "登录成功");
        }
        return Result.error("用户名或密码错误");
    }

    @ApiOperation("用户注册, (着重注意: 若用户选择注册, 并成功后, 务必跳转到登录页面, 成功登录后方可进入具体页面)")
    @PostMapping("signUp")
    public Result signUp(
            @RequestParam("uname") @ApiParam(name = "uname", value = "用户名", required = true) @NotBlank(message = "用户名不能为空") String uname,
            @RequestParam("pass") @ApiParam(name = "pass", value = "密码", required = true) @NotBlank(message = "密码不能为空") String pass,
            @RequestParam("vcode") @ApiParam(name = "vcode", value = "验证码", required = true) @NotBlank(message = "验证码不能为空") String vcode,
            @RequestParam("uid") @ApiParam(name = "uid", value = "验证码uid", required = true) @NotBlank(message = "验证码uid不能为空") String uid
    ) {
        if (redisTemplate.opsForValue().get("vcode::" + uid) == null) {
            return Result.error("验证码已超时");
        }
        if (!redisTemplate.opsForValue().get("vcode::" + uid).equals(vcode)) {
            return Result.error("验证码错误");
        }
        if (userService.checkUname(uname) != 0) {
            return Result.error("昵称已存在");
        }
        User user = new User();
        user.setUname(uname);
        user.setPass(Md5Utils.hash(pass));
        user.setIsvalid((byte) 1);
        int signUp = userService.signUp(user);
        return signUp > 0 ? Result.success("注册成功") : Result.error("注册失败");
    }

    @ApiOperation("修改用户基本信息 (东方启音官网参考, 点击: 用户登录后 --> 首页 --> 顶部右侧 --> 鼠标悬停用户名 --> 个人设置 --> 资料设置; 直达地址: https://www.ostcn.com/ucenter/conf)")
    @PostMapping("updateBaseInfo")
    public Result updateBaseInfo(@RequestParam(name = "uname", required = false) @ApiParam(name = "uname", value = "用户名") String uname,
                                 @RequestParam(name = "personlabel", required = false) @ApiParam(name = "personlabel", value = "个性签名") String personlabel,
                                 HttpServletRequest request
    ) {
        String token = request.getHeader("Authorization");
        if (token == null || redisTemplate.opsForValue().get(token) == null) {
            return Result.error("未发现用户，请先登录或注册");
        }
        User user = (User) redisTemplate.opsForValue().get(token);
        user.setPersonlabel(personlabel);
        if (uname != null) {
            if (userService.checkUname(uname) != 0) {
                return Result.error("昵称已存在");
            }
            user.setUname(uname);
        }
        int update = userService.update(user);
        redisTemplate.opsForValue().set(token, user);
        return update > 0 ? Result.success("修改成功") : Result.error("修改失败");
    }

    @ApiOperation("修改用户手机号 (东方启音官网参考, 点击: 用户登录后 --> 首页 --> 顶部右侧 --> 鼠标悬停用户名 --> 个人设置 --> 资料设置 --> 修改手机; 直达地址: https://www.ostcn.com/ucenter/conf)")
    @PostMapping("updatePhone")
    public Result updatePhone(@RequestParam("phone") @ApiParam(name = "phone", value = "手机号", required = true) @NotBlank(message = "手机号不能为空") String phone,
                              @RequestParam("vcode") @ApiParam(name = "vcode", value = "验证码", required = true) @NotBlank(message = "验证码不能为空") String vcode,
                              @RequestParam("uid") @ApiParam(name = "uid", value = "验证码uid", required = true) @NotBlank(message = "验证码uid不能为空") String uid,
                              HttpServletRequest request
    ) {
        String token = request.getHeader("Authorization");
        if (token == null || redisTemplate.opsForValue().get(token) == null) {
            return Result.error("未发现用户，请先登录或注册");
        }
        if (redisTemplate.opsForValue().get("vcode::" + uid) == null) {
            return Result.error("验证码已超时");
        }
        if (!redisTemplate.opsForValue().get("vcode::" + uid).equals(vcode)) {
            return Result.error("验证码错误");
        }
        if (userService.checkPhone(phone) != 0) {
            return Result.error("手机号已存在");
        }
        User user = (User) redisTemplate.opsForValue().get(token);
        user.setPhone(phone);
        int update = userService.update(user);
        redisTemplate.opsForValue().set(token, user);
        return update > 0 ? Result.success("修改成功") : Result.error("修改失败");
    }

    @ApiOperation("上传用户头像, (东方启音官网参考, 点击: 用户登录后 --> 首页 --> 顶部右侧 --> 鼠标悬停用户名 --> 个人设置 --> 头像修改; 直达地址: https://www.ostcn.com/ucenter/avatar)")
    @PostMapping("avatorUpload")
    public Result avatorUpload(@RequestParam @ApiParam(name = "avatorUpload", value = "头像文件") MultipartFile avatorUpload) {
        if (avatorUpload == null || avatorUpload.isEmpty()) {
            return Result.error("未找到图片！");
        }
        String fileName = avatorUpload.getOriginalFilename();
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        String uuid = UUID.randomUUID().toString();
        fileName = uuid + suffixName;
        File file = new File(imagePath);
        if (!file.exists()) {
            file.mkdir();
        }
        String finalPath = imagePath + "/" + fileName;
        try {
            avatorUpload.transferTo(new File(finalPath));
        } catch (IOException e) {
            e.printStackTrace();
            return Result.error("上传异常");
        }
        return Result.success(fileName, "上传成功");
    }

    @ApiOperation("修改用户密码, (东方启音官网参考, 点击: 用户登录后 --> 首页 --> 顶部右侧 --> 鼠标悬停用户名 --> 个人设置 --> 密码修改; 直达地址: https://www.ostcn.com/ucenter/password)")
    @PostMapping("updatePass")
    public Result updatePass(@RequestParam("oldPass") @ApiParam(name = "oldPass", value = "旧密码", required = true) @NotBlank(message = "旧密码不能为空") String oldPass,
                             @RequestParam("newPass") @ApiParam(name = "newPass", value = "新密码", required = true) @NotBlank(message = "新密码不能为空") String newPass,
                             @RequestParam("checkNewPass") @ApiParam(name = "checkNewPass", value = "确认新密码", required = true) @NotBlank(message = "确认新密码不能为空") String checkNewPass,
                             @RequestParam("vcode") @ApiParam(name = "vcode", value = "验证码", required = true) @NotBlank(message = "验证码不能为空") String vcode,
                             @RequestParam("uid") @ApiParam(name = "uid", value = "验证码uid", required = true) @NotBlank(message = "验证码uid不能为空") String uid,
                             HttpServletRequest request
    ) {
        String token = request.getHeader("Authorization");
        if (token == null || redisTemplate.opsForValue().get(token) == null) {
            return Result.error("未发现用户，请先登录或注册");
        }
        User user = (User) redisTemplate.opsForValue().get(token);
        if (redisTemplate.opsForValue().get("vcode::" + uid) == null) {
            return Result.error("验证码已超时");
        }
        if (!redisTemplate.opsForValue().get("vcode::" + uid).equals(vcode)) {
            return Result.error("验证码错误");
        }
        if (!user.getPass().equals(Md5Utils.hash(oldPass))) {
            return Result.error("原密码输入错误");
        }
        if (!newPass.equals(checkNewPass)) {
            return Result.error("两次新密码不一致");
        }
        if (user.getPass().equals(Md5Utils.hash(newPass))) {
            return Result.error("新密码不得与原先相同");
        }
        user.setPass(Md5Utils.hash(newPass));
        int update = userService.update(user);
        redisTemplate.opsForValue().set(token, user);
        return update > 0 ? Result.success("修改成功") : Result.error("修改失败");
    }

    @ApiOperation("查看用户积分, (东方启音官网参考, 点击: 用户登录后 --> 首页 --> 顶部右侧 --> 鼠标悬停用户名 --> 个人设置 --> 我的积分; 直达地址: https://www.ostcn.com/ucenter/score)")
    @PostMapping("getScore")
    public Result getScore(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token == null || redisTemplate.opsForValue().get(token) == null) {
            return Result.error("未发现用户，请先登录或注册");
        }
        User user = (User) redisTemplate.opsForValue().get(token);
        return Result.success(user.getScore());
    }

    @ApiOperation("获取验证码，用于：登录，注册，更改手机号，更改密码。返回的字段：uid ，picbase64 （使用方式：$.get(window.BASEPATH + 'front/user/genCode', function(result) { $('.codeImage').attr('src', 'data:image/png;base64,' + result.data.picbase64); });） ，注意：所有验证码提交的场景 都需要把返回的uid一并提交")
    @GetMapping("genCode/")
    public Result genCode() throws IOException {
        BufferedImage bi = new BufferedImage(68, 22, BufferedImage.TYPE_INT_RGB);
        Graphics g = bi.getGraphics();
        Color c = new Color(200, 155, 255);
        g.setColor(c);
        g.fillRect(0, 0, 68, 22);
        char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
        Random r = new Random();
        int len = ch.length, index;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4; i++) {
            index = r.nextInt(len);
            g.setColor(new Color(r.nextInt(88), r.nextInt(188), r.nextInt(255)));
            g.drawString(ch[index] + "", (i * 15) + 3, 18);
            sb.append(ch[index]);
        }
        FastByteArrayOutputStream bout = new FastByteArrayOutputStream();
        ImageIO.write(bi, "JPG", bout);
        Map<String, String> map = new HashMap<>();
        String uid = UUID.randomUUID().toString();
        map.put("uid", uid);
        map.put("picbase64", StrUtil.toBase64(bout.toByteArray()));
        this.redisTemplate.opsForValue().set("vcode::" + uid, sb.toString(), Duration.ofSeconds(500));
        return Result.success(map);
    }
}